#include "transContentFuncCallTargetReachable.hpp"

/////////////////////////////////////////////////////////////////////////////////
/// construct packet to stack, use data fifo
/// because this packet has less than 24 bytes, so just use static buffer rather than memory pool
///
///		request packet content format
///		name | length | mainCode | subCode | localPort |target |
///		 len |	  2   |   1      |    1    |   4       |  8    |
///    offset|    0   |   2      |    3    |   4       |  8    |
/// parameter:
///		this method use object field as parameters
///
/// return:
///		E_TRANC_ParamError: need value is invalidate
///		E_TRANC_TIMEOUT: the method timeout
///		E_TRANC_NONBLOCK: the method use sync style
///		result: the query result
/////////////////////////////////////////////////////////////////////////////////////
int TransContentFuncCallTargetReachable::targetReachable(){
	char buffer[20]={0};
	timespec ts = TransContentAssis::TimeTp2Ts(timeout);
	debug_enter();
	if(localPort <= 0 || target.serial_id <= 0){
		logd_error("TransContentFuncCallTargetReachable::targetReachable==> parameter error");
		return E_TRANC_ParamError;
	}
	memset(buffer, 0x00, 20);
	*(short*(buffer)) = (short)14;
	buffer[2] = message_type_inner_functionCall_targetReachable_request;
	*(NodeAddr*(buffer+4)) = localPort;
	*(NodeAddr*(buffer+8)) = target;

	/// send to stack, use data fifo
	TransContentDispatcher::getInstance()->sendDataDataToStack(buffer, 16);

	/// wait or reutrn
	if(tracb != NULL){
		logd_info("TransContentFuncCallTargetReachable::targetReachable==> callback not null, use sync style, the caller return");
		return E_TRANC_NONBLOCK;
	}

	/// wait the condtion value
	pthread_mutex_lock(&waitMutex);
	if(pthread_cond_timedwait(&waitCond, & waitMutex, &tes) == ETIMEDOUT){
		logd_error("funciton call target reachable timed out");
		pthread_mutex_unlock(&waitMutex);
		canBeRemoved = 1;
		return E_TRANC_TIMEOUT;
	}
	pthread_mutex_unlock(&waitMutex);
	canBeRemoved = 1;
	return result;
}

//////////////////////////////////////////////////////////////////////////////////
/// target reachable response
///		extract reachable information from the packet
///
///		request packet content format
///		name | length | mainCode | subCode | localPort |target | result |
///		 len |	  2   |   1      |    1    |   4       |  8    |   1    |
///    offset|    0   |   2      |    3    |   4       |  8    |   16   |
/// parameters:
///		buffer: the packet contain the response information
///		index: the buffer index int he memory pool index
/// return:
///		RESPONSE_RESULT_DELETE_RECORD: delete the record in the port manager
///////////////////////////////////////////////////////////////////////////////////
int TransContentFuncCallTargetReachable::response(char* buffer, int index){
	int mainCode = buffer[0];
	
	debug_enter();
	if(mainCode != message_type_inner_functionCall_targetReachable_response){
		logd_error("function call target reachable, not support main code, post continue");
		return RESPONSE_RESULT_POST_CONITNUE;
	}
	result = buffer[16];
	/// if use sync style, start the new route
	if(tracb != NULL){
		logd_info("response use sync style");
		transContentThreadPool::getInstance()->addTask(finishedRoute, this);
	}else{
		logd_info("response use block style");
		pthread_mutex_lock(&waitMutex);
		pthread_cond_signal(&waitCond);
		pthread_mutex_unlock(&waitMutex);
	}

	transContentMemory::getInstance()->relaseBuffer(index);	
	return RESPONSE_RESULT_NOACTION;
}

void* TransContentFuncCallTargetReachable::finishedRoute(void *p){
	((TransContentFuncCallTargetReachable*)p)->finishIns();
}	

void TransContentFuncCallTargetReachable::finishIns(){
	tracb(result);
	canBeRemoved = 1;
}
